package ch.zhaw.skuh.turing.model.turingmaschine;

import java.math.BigInteger;

import ch.zhaw.skuh.turing.model.turingmaschine.rules.NG_Factorial;

public class NG_Factorial_N_ary extends NG_Multiplication_N_ary {

	public static int COUNTSTATES = 6;
	private static int ACCEPT = 5;

	protected static int STARTSTATE = 3;

	protected static int TAPES = 4;

	private static String NAME = "Factorial, radix=";
	
	private BigInteger input;

	public NG_Factorial_N_ary(int radix) {
		super(radix, new int[] { radix + ACCEPT }, TAPES, COUNTSTATES + radix,
				NAME + Integer.toString(radix));
	}

	public String getCalcResult() {
		// calc factorial
		calcResult = BigInteger.ONE;
		for (BigInteger i = BigInteger.ONE; i.compareTo(input) <= 0; i = i
				.add(BigInteger.ONE)) {
			calcResult = calcResult.multiply(i);
		}
		return calcResult.toString();
	}

	// 1 number, to tapes 1 and 2
	public void setTapes(String input) {
		BigInteger biInput = new BigInteger(input);
		this.input = biInput;
		int[] tapes = new int[] { 0, 1 };
		setTapes(new BigInteger[] { biInput, biInput }, tapes);

		// rules cannot be added until now
		tapes = new int[] { 0, 1, 2, 3 };
		initRules(tapes);
	}

	protected void setTapes(BigInteger[] input, int[] tapes) {
		char[][] charInput = new char[getTapeCount()][];
		int[] pos = new int[getTapeCount()];

		// fill tapes
		for (int i = 0; i < tapes.length; i++) {
			// fill tape
			charInput[tapes[i]] = input[i].toString(radix).toCharArray();
		}
		// set position to last char
		pos[tapes[0]] = charInput[tapes[0]].length - 1;
		// t2 is forwarded by 1
		pos[tapes[1]] = charInput[tapes[1]].length;
		// call super class method (which handles the rest)
		setTapes(charInput, pos, STARTSTATE + radix);
	}

	@Override
	public boolean validateInput(String text) {
		text = text.trim();
		try {
			// test conversion
			new BigInteger(text);
		} catch (NumberFormatException nfe) {
			return false;
		}
		return true;
	}

	// load rule-set
	protected void initRules(int[] tapes) {
		// everything in tapes 1-4
		int[] tapesCurrent = new int[] { tapes[0], tapes[1], tapes[2], tapes[3] };

		// load addition rule-set
		NG_Factorial rules = new NG_Factorial(this);
		rules.setRules(0, radix + ACCEPT, radix + ACCEPT, tapesCurrent);
	}

}
